<?php
namespace Anls\Com\Strategy;
use Anls\Com\Indicator;
use Anls\Common;

/**
 * 策略
 * @author w.
 *
 */
class Main extends AbstractStrategySupport{

    private $Condition = null;
	
	function __construct($bar,$symbolType,$code,$period,$tradeType,$openStrategyExpr,$closeStrategyExpr){
	   
		$this->bar = $bar;
	    $this->symbolType = $symbolType;
	    $this->code = $code;
	    $this->period = $period;
	    $this->tradeType = $tradeType;
	    $this->openStrategyExpr = $openStrategyExpr;
	    $this->closeStrategyExpr = $closeStrategyExpr;
	    
	    
	    $this->initRedis();
	    $this->initRedisKDB();
    }
    

    /**
     * 组装指标
     * 
     */
    private function buildIndicatorData(){
    	// 抽取需要分析的指标，然后初始化指标数据，匹配所有B(...)
		$openIndicKeys = Expr::machKey(Expr::B_REGEX,$this->openStrategyExpr)[1];
		$closeIndicKeys = Expr::machKey(Expr::B_REGEX,$this->closeStrategyExpr)[1];
		$indicKeys = array_merge($openIndicKeys,$closeIndicKeys);
		// 组装指标数据
		$t_total_begin = microtime(true);
		$cnt = count($this->bar)-1;
		$calCnt = 0;
		// 遍历指标表达式键值并计算
		foreach($indicKeys as $key){
		    // 如果最后一个值已存在且第一个值已存在则已统计
            if($this->bar[$cnt][$key] != null && $this->bar[0][$key]!=null) continue;
            for($i=$cnt;$i>=0;$i--){
                $rediskey = 'kdata:'.$this->code . ':' .$this->period.':'. $this->bar[$i]['date'];
    		    $redisVal = $this->redis_k_db->get($rediskey);
    		    if($redisVal != null){
    		        $redisVal = json_decode($redisVal,true);
    		        if($redisVal[$key] != null){
    		            $this->bar[$i][$key] = $redisVal[$key];
    		            continue;
    		        }
    		    } else {
    		        $redisVal = array();
    		    }
    		    
    		    $_key = explode("_", $key)[0];
    		    if($_key == 'open' || $_key == 'high' || $_key == 'low' 
    		        || $_key == 'close' || $_key == 'rise' ) 
    		        continue;
    		    $className = 'Anls\Com\Indicator'.'\\'.$_key;
    		    $methodName = 'calcExpr';
    		    $methodParams = array($this->bar,$key,$i);
    		    $callbackVal = call_user_func_array(array($className,$methodName),$methodParams);
    		    // 设置指标值
    		    if($callbackVal != null){
    		      $this->bar[$i][$key] = $callbackVal;
    		      $redisVal[$key] = $callbackVal;
    		      $this->redis_k_db->set($rediskey,json_encode($redisVal));
    		      $calCnt++;
    		    }
            }
		}
		$t_total_end = microtime(true);
		Common\Log::echoPage($this->code.'组装指标：总'.$cnt.'_计算：'.$calCnt.'测试用时：'.round($t_total_end-$t_total_begin,5).'秒</br>');
    }
    
    /**
     * 组装条件
     * 
     */
    private function buildCondition(){
        $this->Condition = new Condition();
        $this->Condition->setOpenCdtsByExpr($this->openStrategyExpr);
        $this->Condition->setCloseCdtsByExpr($this->closeStrategyExpr);
    }
    
    private function buy($i){
        if($this->buyFlag == false && $this->Condition->checkOpen($this->bar,$i)){
            // 多仓开仓
            array_push($data, $this->bar[$i]['date']);
            // 设置多仓交易数据
            $this->setBuyData($this->bar,$i);
        }
    
        // 多仓数据统计
        if($this->buyFlag == true  && $this->buyOpenDate != $this->bar[$i]['date']){
            // 多仓开仓后数据统计
            $this->statsBuyOpenData($this->bar,$i);
            // 平仓条件
            if($this->Condition->checkClose($this->bar,$i)){
                // 多仓平仓数据统计
                $this->statsBuyCloseData($this->bar,$i);
            }
        }
    }
    
    /**
     * 交易
     */
    public function trade(){
        // 组装指标数据
		$this->buildIndicatorData();
		// 组装条件
		$this->buildCondition();
		
    	// 清楚缓冲数据
        $tradeLogKey = $this->getBuyTradeCacheKey($this->code);
        
        // 重新分析
        // $this->redis->del($tradeLogKey);
  
        // 记录新统计的代码
        $tradeCodeList = $this->redis->lrange($tradeLogKey,0,0);
        $len = count($tradeCodeList);
        if($len == 0) 
        	$this->redis->zAdd($this->getCodeKey(),$this->code,$this->code);
        
        // 开始模拟交易
        $cnt = count($this->bar) - 1;
        $lastLog = $this->redis->lRange($tradeLogKey, -1,-1);
        $i = 0;
        if(count($lastLog)>0){
            // 获取上次最后统计时间
            $lastLog = json_decode($lastLog[0],true);
            $lastCloseDate = $lastLog['buyCloseDate'];
            $lastCloseDate = str_replace('/', '', $lastCloseDate);
            $i = $cnt - 1;	
            for(;$i>=$cnt-100;$i--){
                if($lastCloseDate >= $this->bar[$i]['dateNum']) {
                    $i = $i + 1;
                    break;                 
                }
            }
        }
        for(;$i<$cnt;$i++){
            if($this->tradeType == 'buy'){
                $this->buy($i);
            } else {
                //$this->sell($i);
            }
        }
    }
	
}

?>
